<?php


/**
 * Zender storage class helps to manage global data
 * providing functionality of data locking
 * It use Zend_Registry for normale functionality
 *
 * @category   Zender
 * @package    Zender
 * @subpackage Zender_Core
 * @version 0.0.0
 */
class Zender_Registry {
	
	const MAX_MISTAKE = 5;
	
	/**
	 * Show lock status of registry and lockKey
	 * @var boolean|integer
	 */
	private static $locked = false;
	
	/**
	 * Count the number of wrong attemp to unlock registry
	 * @var integer
	 */
	private static $mistake = 0;
	
	private static $_registry = null;
	
	protected function __costruct() {
		throw new Zender_Exception("You cannot create a Zender_Registry object");
	}
	
	/**
	 * Retrive a stored object if registry is unlocked
     *
     * @param string $index - get the value associated with $index
     * @return mixed
     * @throws Zend_Exception if no entry is registerd for $index or registry is lock
	 */
	public static function get($index) {
		if ( self::isLock() ) {
			throw new Zender_Registry_Exception('Registry is locked. Unlock first');
		} else {
			return self::getInstance()->get($index);
		}
	}
	
	/**
     * Set $value in $index position object if registry is unlocked
     * 
     * @param string $index The location in the ArrayObject in which to store
     *   the value.
     * @param mixed $value The object to store in the ArrayObject.
     * @return void
	 */
	public static function set($index, $value) {
		if ( self::isLock() ) {
			throw new Zender_Registry_Exception('Registry is locked. Unlock first');
		} else {
			return self::getInstance()->set($index, $value);
		}
	}

	/**
	 * Perform a lock op on registry returning lockKey
	 *
	 * @return integer LockKey
	 * @throws Zend_Exception if registry already lock
	 */
	public static function lock() {
		if ( self::isLock() ) {
			throw new Zender_Registry_Exception('Registry already locked');
		} else {
			$lock = rand(10000, 99999);
			self::$locked = $lock;
			self::$mistake = 0;
			return $lock;
		}
	}

	/**
	 * Unlock the use of registry
	 *
	 * @param integer $lockKey The key for unlocking
	 * @throws Zend_Exception if max error exceded or wrong lockKey
	 */
	public static function unLock($lockKey) {
		if ( !self::isLock() ) {
			throw new Zender_Registry_Exception('Registry not locked');
		}
		if ( self::$mistake >= self::MAX_MISTAKE ) {
			// clear all data
			self::getInstance()->_unsetInstance();
			throw new Zender_Registry_Exception('Max error unlocking registry exceded. Registry cleaned');
		} else {
			if ( $lockKey === self::$locked ) {
				self::$locked = false;
				self::$mistake = 0;
				return true;
			} else {
				self::$mistake++;
				throw new Zender_Registry_Exception('Wrong registry lockKey');
			}
		}
	}
	
	/**
	 * Say true if registry is locked
	 *
	 * @return boolean true if locked
	 */
	public static function isLock() {
		return !(self::$locked === false);
	}
	
	/**
	 * Reset registry lock after unsetting it (security reason)
	 *
	 * @param string $resetKey the reset key make with formula md5(md5($lockKey).sha1($lockKey))
	 * @return boolean
	 * @throws Zender_Registry_Exception if reset key is wrong
	 */
	public static function reset($resetKey) {
		if ($resetKey == md5(md5(self::$locked).sha1(self::$locked))) {
			self::getInstance()->_unsetInstance();
			self::$mistake = 0;
			self::$locked = false;
			return true;
		} else {
			throw new Zender_Registry_Exception('Wrong reset key');
		}
	}
	
	/**
	 * Return standard instance of Zend_Registry
	 *
	 * @return Zend_Registry
	 */
	protected static function getInstance() {
		if ( is_null(self::$_registry) ) {
			self::$_registry = new Zend_Registry();
		}
		return self::$_registry;
	}
}